package com.zz.framework.core.utils

import android.content.Context
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.floatPreferencesKey
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.longPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import com.zz.framework.core.BaseApp
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

/**
 * Copyright © 2025 zhun All rights reserved.
 * Created by ZhaoZhun on 2025/3/20 09:31.
 * @author: ZhaoZhun 1820022519@qq.com
 * @version: V1.0
 */


// 定义 DataStore 的名称
const val DATA_STORE_NAME = "ZDataStore"
// 创建 DataStore 实例
val Context.dataStore by preferencesDataStore(name = DATA_STORE_NAME)

class ZDataStore<T>(private val name: String, private val default: T) : ReadWriteProperty<Any?, T> {
    companion object {
        // 清除数据
        suspend fun clear(context: Context) {
            context.dataStore.edit { preferences ->
                preferences.clear()
            }
        }
    }

    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        val flow = getFlow(name, default)
        return kotlinx.coroutines.runBlocking {
            flow.first()
        }
    }

    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        kotlinx.coroutines.runBlocking{
            putPreference(name, value)
        }
    }

    @Suppress("UNCHECKED_CAST")
    private fun <T> getFlow(name: String, default: T): Flow<T> = when (default) {
        is Long -> getLongFlow(name, default)
        is String -> getStringFlow(name, default)
        is Int -> getIntFlow(name, default)
        is Boolean -> getBooleanFlow(name, default)
        is Float -> getFloatFlow(name, default)
        else -> throw IllegalArgumentException("This type can be get from DataStore")
    } as Flow<T>

    private suspend fun <T> putPreference(name: String, value: T) {
        when (value) {
            is Long -> putLong(name, value)
            is String -> putString(name, value)
            is Int -> putInt(name, value)
            is Boolean -> putBoolean(name, value)
            is Float -> putFloat(name, value)
            else -> throw IllegalArgumentException("This type can be saved into DataStore")
        }
    }

    private fun getLongFlow(name: String, default: Long): Flow<Long> {
        val key = longPreferencesKey(name)
        return BaseApp.context.dataStore.data.map { preferences ->
            preferences[key] ?: default
        }
    }

    private fun getStringFlow(name: String, default: String): Flow<String> {
        val key = stringPreferencesKey(name)
        return BaseApp.context.dataStore.data.map { preferences ->
            preferences[key] ?: default
        }
    }

    private fun getIntFlow(name: String, default: Int): Flow<Int> {
        val key = intPreferencesKey(name)
        return BaseApp.context.dataStore.data.map { preferences ->
            preferences[key] ?: default
        }
    }

    private fun getBooleanFlow(name: String, default: Boolean): Flow<Boolean> {
        val key = booleanPreferencesKey(name)
        return BaseApp.context.dataStore.data.map { preferences ->
            preferences[key] ?: default
        }
    }

    private fun getFloatFlow(name: String, default: Float): Flow<Float> {
        val key = floatPreferencesKey(name)
        return BaseApp.context.dataStore.data.map { preferences ->
            preferences[key] ?: default
        }
    }

    private suspend fun putLong(name: String, value: Long) {
        val key = longPreferencesKey(name)
        BaseApp.context.dataStore.edit { preferences ->
            preferences[key] = value
        }
    }

    private suspend fun putString(name: String, value: String) {
        val key = stringPreferencesKey(name)
        BaseApp.context.dataStore.edit { preferences ->
            preferences[key] = value
        }
    }

    private suspend fun putInt(name: String, value: Int) {
        val key = intPreferencesKey(name)
        BaseApp.context.dataStore.edit { preferences ->
            preferences[key] = value
        }
    }

    private suspend fun putBoolean(name: String, value: Boolean) {
        val key = booleanPreferencesKey(name)
        BaseApp.context.dataStore.edit { preferences ->
            preferences[key] = value
        }
    }

    private suspend fun putFloat(name: String, value: Float) {
        val key = floatPreferencesKey(name)
        BaseApp.context.dataStore.edit { preferences ->
            preferences[key] = value
        }
    }
}